From 731a2050ac0eac00af3eaf51bab02e697185a95d Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 7 Nov 2007 14:15:44 +0000 Subject: [PATCH] x86: Fix PV guest CR4 handling. We should not leak hidden CR4 bits into guest CR4 value. Signed-off-by: Keir Fraser --- xen/arch/x86/domain.c | 23 ++++++++++++++--------- xen/arch/x86/traps.c | 3 ++- xen/include/asm-x86/domain.h | 7 +++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 1124dd66a5..aaf7c979c6 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -415,7 +415,8 @@ int vcpu_initialise(struct vcpu *v) v->arch.cr3 = __pa(idle_pg_table); } - v->arch.guest_context.ctrlreg[4] = mmu_cr4_features; + v->arch.guest_context.ctrlreg[4] = + real_cr4_to_pv_guest_cr4(mmu_cr4_features); } v->arch.perdomain_ptes = @@ -573,17 +574,18 @@ void arch_domain_destroy(struct domain *d) unsigned long pv_guest_cr4_fixup(unsigned long guest_cr4) { - unsigned long hv_cr4 = read_cr4(), hv_cr4_mask = ~X86_CR4_TSD; + unsigned long hv_cr4_mask, hv_cr4 = real_cr4_to_pv_guest_cr4(read_cr4()); + + hv_cr4_mask = ~X86_CR4_TSD; if ( cpu_has_de ) hv_cr4_mask &= ~X86_CR4_DE; - if ( (guest_cr4 & hv_cr4_mask) != - (hv_cr4 & hv_cr4_mask & ~(X86_CR4_PGE|X86_CR4_PSE)) ) + if ( (guest_cr4 & hv_cr4_mask) != (hv_cr4 & hv_cr4_mask) ) gdprintk(XENLOG_WARNING, "Attempt to change CR4 flags %08lx -> %08lx\n", hv_cr4 & ~(X86_CR4_PGE|X86_CR4_PSE), guest_cr4); - return (hv_cr4 & hv_cr4_mask) | (guest_cr4 & ~hv_cr4_mask); + return (hv_cr4 & hv_cr4_mask) | (guest_cr4 & ~hv_cr4_mask); } /* This is called by arch_final_setup_guest and do_boot_vcpu */ @@ -684,8 +686,8 @@ int arch_set_info_guest( v->arch.guest_context.user_regs.eflags |= EF_IE; cr4 = v->arch.guest_context.ctrlreg[4]; - v->arch.guest_context.ctrlreg[4] = - (cr4 == 0) ? mmu_cr4_features : pv_guest_cr4_fixup(cr4); + v->arch.guest_context.ctrlreg[4] = cr4 ? pv_guest_cr4_fixup(cr4) : + real_cr4_to_pv_guest_cr4(mmu_cr4_features); memset(v->arch.guest_context.debugreg, 0, sizeof(v->arch.guest_context.debugreg)); @@ -1223,11 +1225,14 @@ static void paravirt_ctxt_switch_from(struct vcpu *v) static void paravirt_ctxt_switch_to(struct vcpu *v) { + unsigned long cr4; + set_int80_direct_trap(v); switch_kernel_stack(v); - if ( unlikely(read_cr4() != v->arch.guest_context.ctrlreg[4]) ) - write_cr4(v->arch.guest_context.ctrlreg[4]); + cr4 = pv_guest_cr4_to_real_cr4(v->arch.guest_context.ctrlreg[4]); + if ( unlikely(cr4 != read_cr4()) ) + write_cr4(cr4); if ( unlikely(v->arch.guest_context.debugreg[7]) ) { diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 32ab678a91..d8a1ec847d 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1797,7 +1797,8 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) case 4: /* Write CR4 */ v->arch.guest_context.ctrlreg[4] = pv_guest_cr4_fixup(*reg); - write_cr4(v->arch.guest_context.ctrlreg[4]); + write_cr4(pv_guest_cr4_to_real_cr4( + v->arch.guest_context.ctrlreg[4])); break; default: diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 28fbd7b1f7..37ff3d5353 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -350,8 +350,15 @@ struct arch_vcpu /* Continue the current hypercall via func(data) on specified cpu. */ int continue_hypercall_on_cpu(int cpu, long (*func)(void *data), void *data); +/* Clean up CR4 bits that are not under guest control. */ unsigned long pv_guest_cr4_fixup(unsigned long guest_cr4); +/* Convert between guest-visible and real CR4 values. */ +#define pv_guest_cr4_to_real_cr4(c) \ + ((c) | (mmu_cr4_features & (X86_CR4_PGE | X86_CR4_PSE))) +#define real_cr4_to_pv_guest_cr4(c) \ + ((c) & ~(X86_CR4_PGE | X86_CR4_PSE)) + #endif /* __ASM_DOMAIN_H__ */ /* -- 2.30.2